package io.xxx.xbutler.core.check;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.hy.corecode.idgen.WFGIdGenerator;
import io.xxx.xbutler.common.RedisKeys;
import io.xxx.xbutler.data.StoreSettingsMapper;
import io.xxx.xbutler.domain.RoomCategory;
import io.xxx.xbutler.domain.Store;
import io.xxx.xbutler.domain.StoreSettings;
import io.xxx.xbutler.domain.task.PushContext;
import io.xxx.xbutler.domain.task.Receiver;
import io.xxx.xbutler.domain.task.Task;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RAtomicLong;
import org.redisson.api.RedissonClient;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Objects;

@Slf4j
@Order(60)
@Component
public class PushChecker implements Checker {

    @Resource
    private WFGIdGenerator idGenerator;

    @Resource
    private RedissonClient redissonClient;

    @Resource
    private StoreSettingsMapper storeSettingsMapper;

    @Override
    public CheckError check(PushContext context) {
        LocalDateTime now = LocalDateTime.now();
        LocalTime currentTime = now.toLocalTime();

        Task task = context.getTask();
        Receiver receiver = context.getReceiver();
        Store store = context.getStore();
        StoreSettings storeSettings = getStoreSettings(store);

        // 开关
        if (storeSettings.isPushEnabled()) {
            CheckError error = CheckError.StorePushNotEnabled;
            log.info("{}门店推送已关闭[taskId:{}, storeId:{}, storeCode:{}]", error.getErrorMessage(), task.getId(), store.getId(), store.getCode());
            return error;
        }

        // 推送时间范围
        if (!task.getIgnorePushInterval()) {
            LocalTime startPushTime = storeSettings.getStartPushTime();
            LocalTime endPushTime = storeSettings.getEndPushTime();
            if (currentTime.isBefore(startPushTime) || currentTime.isAfter(endPushTime)) {
                CheckError error = CheckError.StorePushTimeExceeded;
                log.info("{}[taskId:{}, storeId:{}, storeCode:{}, currentTime:{}, startPushTime:{}, endPushTime:{}]", error.getErrorMessage(), task.getId(), receiver.getStoreId(), receiver.getStoreCode(), currentTime, startPushTime, endPushTime);
                return error;
            }
        }

        // 推送数量
        if (!task.getIgnorePushQuantity()) {
            RAtomicLong miniProgramPushedQuantity = redissonClient.getAtomicLong(RedisKeys.miniProgramPushedQuantity(receiver.getStoreId(), now.toLocalDate()));
            if (miniProgramPushedQuantity.get() > storeSettings.getMaxPushQuantity()) {
                CheckError error = CheckError.StoreMaxPushQuantityReached;
                log.info("{}[taskId:{}, storeId:{}, storeCode:{}, maxPushQuantity:{}]", error.getErrorMessage(), task.getId(), receiver.getStoreId(), receiver.getStoreCode(), storeSettings.getMaxPushQuantity());
                return error;
            }
        }
        return null;
    }

    @Nonnull
    private StoreSettings getStoreSettings(Store store) {
        Long storeId = store.getId();
        LambdaQueryWrapper<StoreSettings> wrapper = new LambdaQueryWrapper<StoreSettings>()
                .eq(StoreSettings::getStoreId, storeId);
        StoreSettings storeSettings = storeSettingsMapper.selectOne(wrapper);
        if (Objects.isNull(storeSettings)) {
            LocalDateTime now = LocalDateTime.now();
            storeSettings = new StoreSettings()
                    .setId(idGenerator.next())
                    .setStoreId(storeId)
                    .setStoreCode(store.getCode())
                    .setStartPushTime(LocalTime.of(8, 0))
                    .setEndPushTime(LocalTime.of(22, 0))
                    .setMaxPushQuantity(20)
                    .setCreatedTime(now)
                    .setUpdatedTime(now);
            try {
                storeSettingsMapper.insert(storeSettings);
            } catch (Exception e) {
                log.warn("保存门店默认设置发送异常[storeId:{}]", store.getId(), e);
            }
        }
        return storeSettings;
    }

    @Override
    public boolean supports(PushContext context) {
        Task task = context.getTask();
        return task.getRoomCategory() == RoomCategory.CustomerRoom && context.getStore() != null;
    }
}
